package com.ybear.ybutils.utils;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Log;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 日志类
 */
public class LogUtil {
    @IntDef({ LogType.V, LogType.D, LogType.I, LogType.W, LogType.E })
    @Retention(RetentionPolicy.SOURCE)
    public @interface LogType {
        int V = 5;
        int D = 4;
        int I = 3;
        int W = 2;
        int E = 1;
    }

    public interface CallLog {
        void call(@NonNull String tag, @NonNull String message, @LogType int type);
    }

    private static final String TAG = "YB_TAG";

    private static String mTagOfGlobal = null;
    private static boolean isDebug = true;
    private static boolean isCall = false;

    private static CallLog mCallLog;
    /**
     * 设置全局打印的tag
     * @param tag   tag
     */
    public static void setTagOfGlobal(@NonNull String tag) { mTagOfGlobal = tag; }

    /**
     * 是否处于调试模式
     * @return      结果
     */
    public static boolean isDebug() { return isDebug; }

    /**
     * 允许启用输出日志功能
     * @param enable        正式环境（release）下不会输出日志（false）。
     *                      除非你在manifest的application中配置：android:debuggable="true"
     * @param isAuto        无视<code>enable</code>的说明
     */
    public static void setDebugEnable(@NonNull Context context, boolean enable, boolean isAuto) {
        if( isAuto ) {
            int flag = ApplicationInfo.FLAG_DEBUGGABLE;
            //第二个判断意味着传入true时会验证当前环境是否也处于调试模式，非调试模式时为false
            isDebug = enable && ( context.getApplicationInfo().flags & flag ) == flag;
        } else {
            isDebug = enable;
        }
    }

    public static void setDebugEnable(@NonNull Context context, boolean enable) {
        setDebugEnable( context, enable, false );
    }

    public static void setDebugEnableOfAuto(@NonNull Context context) {
        setDebugEnable( context, true, true );
    }

    /**
     * 是否允许启用日志保存功能
     * @param enable    是否启用
     */
    public static void setCallLogEnable(boolean enable) {
        isCall = enable;
    }

    /**
     * 启用日志后会回调日志接口，保存操作交付给开发者自行保存
     * @param call  回调
     */
    public static void setOnCallListener(CallLog call) {
        mCallLog = call;
    }

    public static int v(@Nullable String tag, @Nullable String msg) {
        return printLog( tag, msg, LogType.V );
    }
    public static int d(@Nullable String tag, @Nullable String msg) {
        return printLog( tag, msg, LogType.D );
    }
    public static int i(@Nullable String tag, @Nullable String msg) {
        return printLog( tag, msg, LogType.I );
    }
    public static int w(@Nullable String tag, @Nullable String msg) {
        return printLog( tag, msg, LogType.W );
    }
    public static int e(@Nullable String tag, @Nullable String msg) {
        return printLog( tag, msg, LogType.E );
    }

    public static int v(@NonNull Class<?> cls, @Nullable String msg) {
        return printLog( cls.getSimpleName(), msg, LogType.V );
    }
    public static int d(@NonNull Class<?> cls, @Nullable String msg) {
        return printLog( cls.getSimpleName(), msg, LogType.D );
    }
    public static int i(@NonNull Class<?> cls, @Nullable String msg) {
        return printLog( cls.getSimpleName(), msg, LogType.I );
    }
    public static int w(@NonNull Class<?> cls, @Nullable String msg) {
        return printLog( cls.getSimpleName(), msg, LogType.W );
    }
    public static int e(@NonNull Class<?> cls, @Nullable String msg) {
        return printLog( cls.getSimpleName(), msg, LogType.E );
    }

    public static int v(String msg) { return v( (String) null, msg ); }
    public static int d(String msg) { return d( (String) null, msg ); }
    public static int i(String msg) { return i( (String) null, msg ); }
    public static int w(String msg) { return w( (String) null, msg ); }
    public static int e(String msg) { return e( (String) null, msg ); }

    /**
     * 根据类型打印日志
     * @param msg   msg
     * @param type  type
     */
    private static int printLog(@Nullable String tag, @Nullable String msg, @LogType int type) {
        tag = ( mTagOfGlobal == null ? TAG : mTagOfGlobal ) + ( tag == null ? "" : "_" + tag );
        msg = msg == null ? "" : msg;

        if( isCall ) callLog( tag, msg, type );

        if( !isDebug ) return -1;

        int index = 0;
        int maxLen = 4000;          //logcat单次最大字节容量
        int msgLen = msg.length();
        String subMsg;
        int ret = 0;
        while( index < msgLen ) {
            //分割日志
            subMsg = msg.substring( index, Math.min( msgLen, index + maxLen ) );
            //输出日志
            ret = printTypeLog( tag, subMsg, type );
            index += maxLen;
        }
        return ret;
    }

    private static int printTypeLog(@NonNull String tag, @NonNull String msg, @LogType int type) {
        if ( type == LogType.D ) return Log.d( tag, msg );
        if ( type == LogType.I ) return Log.i( tag, msg );
        if ( type == LogType.W ) return Log.w( tag, msg );
        if ( type == LogType.E ) return Log.e( tag, msg );
        return Log.v( tag, msg );
    }

    /**
     * 保存日志
     * @param msg   日志内容
     * @param type  日志类型
     */
    private static void callLog(@NonNull String tag, @NonNull String msg, @LogType int type) {
        if( mCallLog != null ) mCallLog.call(tag, msg, type);
    }
}